var utils = module.exports;

var log = console.log;

// control variable of func "myPrint"
// var isPrintFlag = false;
var isPrintFlag = true;

/**
 * Check and invoke callback function
 */
utils.invokeCallback = function (cb) {
    if (!!cb && typeof cb === 'function') {
        cb.apply(null, Array.prototype.slice.call(arguments, 1));
    }
};

/**
 * clone an object
 */
utils.clone = function (origin) {
    if (!origin) {
        return;
    }

    var obj = {};
    for (var f in origin) {
        if (origin.hasOwnProperty(f)) {
            obj[f] = origin[f];
        }
    }
    return obj;
};

utils.size = function (obj) {
    if (!obj) {
        return 0;
    }

    var size = 0;
    for (var f in obj) {
        if (obj.hasOwnProperty(f)) {
            size++;
        }
    }

    return size;
};

// print the file name and the line number ~ begin
function getStack() {
    var orig = Error.prepareStackTrace;
    Error.prepareStackTrace = function (_, stack) {
        return stack;
    };
    var err = new Error();
    Error.captureStackTrace(err, arguments.callee);
    var stack = err.stack;
    Error.prepareStackTrace = orig;
    return stack;
}

function getFileName(stack) {
    return stack[1].getFileName();
}

function getLineNumber(stack) {
    return stack[1].getLineNumber();
}

utils.myPrint = function () {
    if (isPrintFlag) {
        var len = arguments.length;
        if (len <= 0) {
            return;
        }
        var stack = getStack();
        var aimStr = '\'' + getFileName(stack) + '\' @' + getLineNumber(stack) + ' :\n';
        for (var i = 0; i < len; ++i) {
            aimStr += arguments[i] + ' ';
        }
        console.log('\n' + aimStr);
    }
};


utils.checkObjUndefined = function (obj) {
    for (var k in obj) {
        if (!obj[k]) {
            return false;
        }
    }
    return true;
};

utils.getIPFromSession = function (session) {
    // session.__session__.__socket__.remoteAddress = { ip: '::ffff:192.168.0.112', port: 58402 }
    var ip = session.__session__.__socket__.remoteAddress.ip;
    return ip;  // 不再从ipv6中解析，直接记录全部ip
    // return utils.getIPFromIPv6(ip);
};

utils.getIPFromIPv6 = function (IPv6) {
    var lastIndex = IPv6.lastIndexOf(':');
    var ip = IPv6.substring(lastIndex + 1);
    return ip;
};

// 生成随机的名字
utils.genName = function () {
    var name = '';
    name = randomChars(3, 'abcdefghijkmnpqrstuvwxyz') + randomChars(6, '0123456789');
    return name;
};

// 生成平均分布的 [min, max] 区间的数字
utils.genRandomNum = function (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
    // return Math.floor(Math.random() * (max - min)) + min; // [min, max) // 不包括max
    // return Math.ceil(Math.random() * (max - min + 1)) + min; // (min, max] // 不包括min
};

// 生成随机字符串
function randomChars(charsLength, chars) {

    var length = charsLength;

    if (!chars) {
        chars = "abcdefghijkmnpqrstuvwxyzABCDEFGHIJKMNPQRSTUVWXYZ0123456789";
    }
    var randomChars = "";
    for (var x = 0; x < length; x++) {
        var i = Math.floor(Math.random() * chars.length);
        randomChars += chars.charAt(i);
    }
    return randomChars;
}

// 返回概率结果
// in: some, all  1,100
// out: true || false  true = some/all = 1/100
// 意义： 有 1/100 的可能
utils.probability = function (some, all) {
    // 输入不是数字，返回false
    if (typeof some !== 'number' && typeof all !== 'number') {
        return false;
    }

    // 分子不小于分母，返回true
    if (some >= all) {
        return true;
    }

    var prob = some / all;
    return Math.random() < prob;
};

/**
 * 2016年12月19日
 * probability的延迟求值版本
 * var b = a(1, 2);
 * 此后就可以用b()来获取1/2的概率
 * 用b = null来释放掉内存
 */
utils.genProbability = function (some, all) {
    var isArgsRight = true;
    // 输入不是数字，返回false
    if (typeof some !== 'number' && typeof all !== 'number') {
        isArgsRight = false;
    }

    // 分子不小于分母，返回false
    if (some >= all) {
        isArgsRight = false;
    }

    return function () {

        if (!isArgsRight) {
            return false;
        }

        var prob = some / all;
        return Math.random() > prob;
    };
};

/**
 * 2016年12月20日
 * 综合下注概率
 * in: pos (下注位置)
 * out: bool  是否下注
 */

utils.checkBid = function (pos) {

    var pNature = utils.genProbability(1, 3);
    var pPair = utils.genProbability(1, 9);
    var pDraw = utils.genProbability(1, 12);
    var pDrawPair = utils.genProbability(1, 33);

    // 0闲对子 1闲赢 2闲天王 3平 4同点平 5庄对子 6庄赢 7庄天王
    // var pro = {
    //     0: 48,
    //     1: 2,
    //     2: 20,
    //     3: 36,
    //     4: 132,
    //     5: 48,
    //     6: 2,
    //     7: 20
    // };  // 赔率。用赔率来做概率

    // 0闲 1和 2庄 3大 4闲天王 5闲对子 6庄对子 7庄天王 8小
    // 2   9   2   2.5  3     12       12     3      1.5
    var pro = {
        0: 2,
        1: 9,
        2: 2,
        3: 3,
        4: 5,
        5: 12,
        6: 12,
        7: 5,
        8: 2
    };  // 赔率。用赔率来做概率。
    return utils.probability(1, pro[pos]);
};

/**
 * 把牌从数字转为十六进制字符串
 * card: 牌的数字
 * num: 牌的总数： 52或者54, 默认为52
 */
utils.genCardStr = function (card, num) {
    card = parseInt(card);
    num = num || 52;

    if (isNaN(card)) {
        return '';
    }

    var str = '0x';
    var suit = (card % 52).toString();
    var point = (card % 13).toString(16);

    return str + suit + point;
};

/**
 * 把一组牌从数字转为十六进制字符串
 * cards`: 牌的数字数组
 * num: 牌的总数： 52或者54, 默认为52
 */
utils.genCardsStr = function (cards, num) {
    num = num || 52;
    var rel = '';

    cards.forEach(function (val, idx, arr) {
        var str = '0x';
        var suit = (val % 52).toString();
        var point = (val % 13).toString(16);
        rel += str;
    });

    return rel;
};


// 返回棋局结果文字版
utils.roundResultWords = function (result) {

    var rel = result.result;
    var round = result.round;
    var points = result.points;

    var ret = '';

    if (rel.winner === 'banker') {
        ret += '庄赢,';
    } else if (rel.winner === 'player') {
        ret += '闲赢,';
    } else {
        ret += '平局,';
    }

    if (rel.bankerPair && rel.playerPair) {
        ret += '全对子,';
    } else if (rel.bankerPair && !rel.playerPair) {
        ret += '庄对子,';
    } else if (!rel.bankerPair && rel.playerPair) {
        ret += '闲对子,';
    }

    // if (!round.banker[3] && !round.player[3]) {
    // 不再限制一定得只有两张牌
    if (rel.bNature) {
        ret += '庄天王,';
    }
    if (rel.pNature) {
        ret += '闲天王,';
    }
    // }

    // 不再要同点平    
    // if (ret.indexOf('平局') > -1 && ret.indexOf('全对子') > -1) {
    //     ret += '同点平';
    // }

    if (rel.type === 0) {
        ret += '小';
    }
    else if (rel.type === 1) {
        ret += '大';
    }

    return ret;
};

utils.getRealPoint = function (player) {
    var card1 = player[1];
    var card2 = player[2];

    var point = 0;

    card1 = parseInt(card1.substring(1));
    card1 = card1 > 9 ? 0 : card1;
    card2 = parseInt(card2.substring(1));
    card2 = card2 > 9 ? 0 : card2;

    point = point + card1 + card2;

    point = point > 9 ? point - 10 : point;

    return point;
};

/**
 * 根据value删除数组中的值
 * in: value: 待删除的元素的值； list: 待处理数组；
 */
utils.removeByVal = function (value, list) {
    list.forEach(function (val, idx, arr) {
        if (val === value) {
            arr.splice(idx, 1);
        }
    });
};

/**
 * 根据index删除数组中的一个值
 * in: index: 待删除的元素的值； list: 待处理数组；
 */
utils.removeByIdx = function (index, list) {
    list.forEach(function (val, idx, arr) {
        if (idx === index) {
            arr.splice(idx, 1);
        }
    });
};

/**
 * 根据值或者索引删除数组中的一个元素
 */
utils.removeArr = function (value, index, list) {
    if (value) {
        utils.removeByVal(value, list);
    } else if (index) {
        utils.removeByIdx(value, list);
    }
};

/**
 * 根据配置删除数组中的一个元素
 * {val: value, idx: index, all: false}
 */
utils.removeArrByOpts = function (opts, list) {
    if (opts.val) {
        utils.removeByVal(opts.val, list, opts.all);
    } else if (opts.idx) {
        utils.removeByIdx(opts.idx, list);
    }
};

/**
 * 扁平化对象
 */
utils.flatten = function (data) {
    log('flatten');
    log(data);
    var result = {};

    function recurse(cur, prop) {
        if (Object(cur) !== cur) {
            // 判断简单对象
            result[prop] = cur;
        }
        else if (Array.isArray(cur)) {
            for (var i = 0, l = cur.length; i < l; i++) {
                recurse(cur[i], prop + "[" + i + "]");
            }
            if (l === 0) {
                result[prop] = [];
            }
        }
        else {
            var isEmpty = true;
            for (var p in cur) {
                isEmpty = false;
                recurse(cur[p], prop ? prop + "." + p : p);
            }
            if (isEmpty && prop) {
                result[prop] = {};
            }
        }
    }
    recurse(data, "");
    log(result);
    return result;
};


/**
 * 左边补齐对应字符串
 * strs: 原字符串, len: 要返回的字符串的长度, str: 填充的字符
 */
utils.leftPad = function (strs, len, str) {
    if (!len || len <= 0) {
        return strs;
    }
    var l = strs.length;
    if (l >= len) {
        return strs;
    }
    for (var i = l; i < len; i++) {
        strs = str + strs;
    }
    return strs;
};

/**
 * 返回数组中最大的元素的值和索引
 */
utils.arrMax = function (arr, cb) {
    var val = arr[0];
    var idx = 0;
    for (var i = 0, len = arr.length; i < len; i++) {
        if (val < arr[i]) {
            val = arr[i];
            idx = i;
        }
    }
    if (typeof cb === 'function') {
        cb(val, idx);
    }
    else {
        return { val, idx };
    }
};

// 把数组转化为对象，如果数组的值中间有等号，则把等号前面的作为key,后面的作为value
utils.getObjFromArr = (arr, cb) => {
    var obj = {};
    for (let val of arr) {
        let count = 0, done = 0, idx = -1;
        val = val.toString();  // 转为字符串再用字符串的原型函数
        if (val.indexOf('=') === -1) {
            while (!done) {
                if (!obj[count]) {
                    obj[count] = val;
                    done = 1;
                }
                else {
                    count++;
                }
            }
        }
        else {
            idx = val.indexOf('=');
            // 使用截取字符串而不是 split('=')[0] 和 [1]，防止字符串中有多个 =
            obj[val.substring(0, idx)] = val.substring(idx + 1);
        }
    }
    return typeof cb === 'function' ? cb(obj) : obj;
};

// 从分转化为元
utils.getYuan = (num) => {
    if (isNaN(num) || parseInt(num) === 0) {
        return 0;
    }
    num = parseInt(num);
    return num / 100;
};

// 从元转化为分
utils.getFen = (num) => {
    if (isNaN(num) || parseInt(num) === 0) {
        return 0;
    }
    num = parseInt(num);    
    return num * 100;
};

// 检查一个数组中的数字是否都是正整数
utils.checkPosIntList = (numList) => {
    if (!Array.isArray(numList)) {
        return false;
    }
    for (k of numList) {
        if (isNaN(k) || k <= 0) {
            return false;
        }
    }
    return true;
};

// 检查一个数组中的数字是否都是正整数或者可以转化为正整数
utils.checkPosIntOrStr = (num) => {
    num = parseInt(num);
    if (isNaN(num) || num <= 0) {
            return false;
        }
    return true;
};
